package cn.mesmile.amqp.config;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author zb
 * @date 2021/3/15 21:28
 * @Description:
 */
@Configuration
public class RabbitMQConfig {


    /**
     * 开启 【生产者】到【消费者】 手动签收确认后，一个RabbitTemplate对象只支持一个回调
     *
     * 所有@Scope("prototype")设置多例
     *
     * 消息投递手动签收 Only one ConfirmCallback is supported by each RabbitTemplate
     * 由于spring的Bean默认都是单例的，这个RabbitTemplate也不例外，既然每个RabbitTemplate对象只支持一个回调，那我就在该Bean放入spring容器把该RabbitTemplate
     * 设置为原型的(也就是@Scope=“prototype”),具体代码如下
     *
     * 生产者传过去的实体类对象需要实现序列化 implements Serializable
     *
     * @param connectionFactory
     * @return
     */
//    @Bean
//    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
//    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
//        boolean publisherConfirms = connectionFactory.isPublisherConfirms();
//        // 确认开启ConfirmCallback
//        System.out.println("publisherConfirms = " + publisherConfirms);
//        // 确认开启ConfirmCallback回调
//        System.out.println("connectionFactory.isPublisherReturns() = " + connectionFactory.isPublisherReturns());
//
//        CachingConnectionFactory connectionFactory2 = (CachingConnectionFactory) connectionFactory;
//        // rabbitMq新版本开启 ReturnCallback
//        connectionFactory2.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);
//
//
//        // // rabbitMq新版本开启 ReturnCallback
//        //connectionFactory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);
//
//
//        RabbitTemplate template = new RabbitTemplate(connectionFactory2);
//        // 为true,则交换机处理消息到路由失败，则会返回给生产者
//        template.setMandatory(true);
////        template.setMessageConverter(new SerializerMessageConverter());
//        // 解决乱码问题
////        template.setMessageConverter(new Jackson2JsonMessageConverter());
//        return template;
//    }
//
//    /**
//     *  此处设置，将对象以json的方式发送出去，存储在队列中
//     *  若不配置默认是对象序列化以后发送出去，在rabbitmq web端看到队列中存储的是一串序列化后的乱码
//     * @return
//     */
//    @Bean
//    public MessageConverter messageConverter() {
//        return new Jackson2JsonMessageConverter();
//    }
//
//
//    /**
//     *  配置消息监听者
//     * @param connectionFactory
//     * @return
//     */
//    @Bean
//    public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory) {
//        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
//        //同时监听多个队列
////        container.setQueues(directRabbitMqQueue());
//        //设置当前的消费者数量
////        container.setConcurrentConsumers(1);
//        //设置当前的消费者数量上限
////        container.setMaxConcurrentConsumers(5);
//        //设置是否重回队列
//        container.setDefaultRequeueRejected(true);
//        //设置手动签收 --》 这里指定确认方式 Auto为自动  MANUAL为手动
//        container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
//        //设置监听外露
//        container.setExposeListenerChannel(true);
//        //设置消息监听
////        container.setMessageListener(fooMessageListener());
//        return container;
//    }



    /**
     *
     *  业务场景： 新商家注册成功后,需要在30天内上传商品，否则就暂时禁用
     *
     *  商家交换机   -->   商家队列[设置死信交换机，死信路由键，过期时间]   -->    死信消息交换机   -->  死信队列
     *  new.merchant.exchange ->  new.merchant.queue  ->  lock_merchant_dead_exchange  -> lock_merchant_dead_queue
     *
     * 死信交换机
     */
    public static final String LOCK_MERCHANT_DEAD_EXCHANGE = "lock_merchant_dead_exchange";

    /**
     * 死信对列
     */
    public static final String LOCK_MERCHANT_DEAD_QUEUE = "lock_merchant_dead_queue";

    /**
     * 死信对列 路由key
     */
    public static final String LOCK_MERCHANT_ROUTING_KEY = "lock_merchant_routing_key";


    /**
     * 死信交换机
     * @return
     */
    @Bean
    public Exchange lockMerchantDeadExchange(){
        return new TopicExchange(LOCK_MERCHANT_DEAD_EXCHANGE, true, false);
    }

    /**
     * 死信队列
     * @return
     */
    @Bean
    public Queue lockMerchantDeadQueue(){
        return QueueBuilder.durable(LOCK_MERCHANT_DEAD_QUEUE)
//                 .deadLetterExchange("")  // 设置死信交换机
//                 .deadLetterRoutingKey("") // 设置死信路由key
//                 .ttl(10000) // 队列中消息的过期时间
                .build();
    }

    /**
     *  交换机绑定队列   # 一个或多个字符     * 一个字符
     * @param queue
     * @param exchange
     * @return
     */
    @Bean
    public Binding lockMerchantDeadBinding(){
        return BindingBuilder.bind(lockMerchantDeadQueue()).to(lockMerchantDeadExchange()).with(LOCK_MERCHANT_ROUTING_KEY).noargs();
    }



    /**
     *  new_merchant_queue -> 死信消息交换机 -> 死信队列
     *
     * 新商家
     */
    public static final String NEW_MERCHANT_EXCHANGE = "new.merchant.exchange";

    /**
     * 商家对应队列
     */
    public static final String NEW_MERCHANT_QUEUE = "new.merchant.queue";

    /**
     * 商家对应 路由key
     */
    public static final String NEW_MERCHANT_ROUTING_KEY = "new.merchant.#";


    /**
     * 新商家交换机
     * @return
     */
    @Bean
    public Exchange newMerchantExchange(){
        return new TopicExchange(NEW_MERCHANT_EXCHANGE, true, false);
    }

    /**
     * 新商家队列
     * @return
     */
    @Bean
    public Queue newMerchantQueue(){
        return QueueBuilder.durable(NEW_MERCHANT_QUEUE)
                 .deadLetterExchange(LOCK_MERCHANT_DEAD_EXCHANGE)  // 设置死信交换机
                 .deadLetterRoutingKey(LOCK_MERCHANT_ROUTING_KEY) // 设置死信路由key
                 .ttl(20000) // 队列中消息的过期时间单位 ms
                .build();
    }

    /**
     *  新商家绑定队列   # 一个或多个字符     * 一个字符
     * @param queue
     * @param exchange
     * @return
     */
    @Bean
    public Binding newMerchantBinding(){
        return BindingBuilder
                .bind(newMerchantQueue())
                .to(newMerchantExchange())
                .with(NEW_MERCHANT_ROUTING_KEY)
                .noargs();
    }



    /////////////////////////////////////////////////////////////////////////////

    /**
     * 交换机
     */
    public static final String EXCHANGE_NAME="order_change";

    /**
     * 队列
     */
    public static final String QUEUE_NAME="order_queue";


    /**
     * 交换机
     * @return
     */
    @Bean
    public Exchange orderExchange(){
        return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();
    }

    /**
     * 队列
     * @return
     */
    @Bean
    public Queue orderQueue(){
        return QueueBuilder.durable(QUEUE_NAME)
//                 .deadLetterExchange("")  // 设置死信交换机
//                 .deadLetterRoutingKey("") // 设置死信路由key
//                 .ttl(10000) // 队列中消息的过期时间
                 .build();
    }

    /**
     *  交换机绑定队列   # 一个或多个字符     * 一个字符
     * @param queue
     * @param exchange
     * @return
     *
     * Queue queue, Exchange exchange
     */
    @Bean
    public Binding orderBinding(){
        return BindingBuilder.bind(orderQueue()).to(orderExchange()).with("order.#").noargs();
    }

    /////////////////////////////////////////////////////////////////////////////

    /**
     * 交换机
     */
    public static final String EXCHANGE_NAME_TEST="test_change";

    /**
     * 队列
     */
    public static final String QUEUE_NAME_TEST="test_queue";


    /**
     * 交换机
     * @return
     */
    @Bean
    public Exchange testExchange(){
        return ExchangeBuilder.topicExchange(EXCHANGE_NAME_TEST).durable(true).build();
    }

    /**
     * 队列
     * @return
     */
    @Bean
    public Queue testQueue(){
        return QueueBuilder.durable(QUEUE_NAME_TEST)
//                 .deadLetterExchange("")  // 设置死信交换机
//                 .deadLetterRoutingKey("") // 设置死信路由key
//                 .ttl(10000) // 队列中消息的过期时间
                .build();
    }

    /**
     *  交换机绑定队列   # 一个或多个字符     * 一个字符
     * @param queue
     * @param exchange
     * @return
     *
     * Queue queue, Exchange exchange
     */
    @Bean
    public Binding testBinding(){
        return BindingBuilder.bind(testQueue()).to(testExchange()).with("test.#").noargs();
    }

}
